package bg.btanev.eightyfour.dao;

import java.io.Serializable;
import java.util.List;

import org.hibernate.criterion.DetachedCriteria;

import bg.btanev.eightyfour.dao.exception.AttachEntityException;
import bg.btanev.eightyfour.domain.entitybase.DomainEntity;
import bg.btanev.eightyfour.domain.entitybase.DomainValue;

/**
 * The generic DAO interface.
 *
 * @author B. Tanev
 * @param <E>
 *            Type of the {@link DomainEntity} object for the current DAO instance.
 * @param <ID>
 *            the {@link DomainEntity} unique identifier type.
 */
public interface GenericDAO<ID extends Serializable, E extends DomainEntity<ID>> {

	/**
	 * Persists or update persistent {@link DomainEntity}.
	 *
	 * @param entity
	 *            entity to save
	 */
	void saveUpdateEntity(E entity);

	/**
	 * Deletes an entity form database.
	 *
	 * @param entity
	 *            entity to be deleted
	 */
	void delete(E entity);

	/**
	 * Flush and clear the current session.
	 */
	void flushAndClearSession();

	/**
	 * Flushes the hibernate session.
	 */
	void flush();

	/**
	 * Clears the current session
	 */
	void clearSession();

	/**
	 * @param entity
	 * @return
	 */
	E refresh(E entity);

	/**
	 * Detaches a persistent {@link DomainValue} entity from the current session.
	 *
	 * @param entity
	 *            entity to be detached.
	 */
	void detach(E entity);

	/**
	 * @param entity
	 * @return
	 */
	E lock(E entity);

	/**
	 *
	 * @param entity
	 * @return
	 */
	E update(E entity);

	/**
	 *
	 * @param entity
	 * @return
	 */
	E merge(E entity);

	/**
	 * <p>
	 * Attach an entity to the current session.
	 * </p>
	 * <p>
	 * Trying to attach the entity with using <code>lock()</code>. If lock fails entities merging (<code>merge()</code>)
	 * is performed.
	 * </p>
	 *
	 * @param entity
	 *            the entity that will be attached to the hibernate session.
	 * @throws AttachEntityException
	 *             when the entity cannot be attached to the hibernate session.
	 */
	E attach(E entity) throws AttachEntityException;

	/**
	 * Creates a {@link DetachedCriteria} for the entity.
	 *
	 * @return the detached criteria.
	 */
	DetachedCriteria createDetachedCriteria();

	/**
	 * Finds a POJO by specified id.
	 *
	 * @param id
	 *            id of the POJO to be found
	 * @return POJO for the given id or <code>null</code> if the POJO cannot be found.
	 */
	E findById(ID id);

	/**
	 * Lists all the entities.
	 *
	 * @return a {@link List} of all the entities.
	 */
	List<E> findAll();

	/**
	 * List all entities order by the unique identifier.
	 *
	 * @param idOrderDesc
	 *            <code>true</code> if the result {@link List} will be ordered descending otherwise <code>false</code>.
	 * @return an ordered {@link List} of all entities.
	 */
	List<E> findAll(boolean idOrderDesc);

	/**
	 * @param detachedCriteria
	 *            the search criteria as {@link DetachedCriteria}
	 * @return the criteria result as {@link List}
	 */
	List<E> findByCriteria(DetachedCriteria detachedCriteria);

	/**
	 *
	 * @param detachedCriteria
	 * @param paging
	 * @return
	 */
	List<E> findByCriteria(DetachedCriteria detachedCriteria, PagingConfig paging);

	/**
	 * @param propertyName
	 *            the unique property name
	 * @param searchValue
	 *            the unique searched value
	 * @return the searched entity
	 */
	E findByUniqueProperty(String propertyName, Object searchValue);

	/**
	 *
	 * @param propertyName
	 *            the property name
	 * @param propertyValue
	 *            the searched property value
	 * @return list of entities searched by "EQ"
	 */
	List<E> findByPropertyName(String propertyName, Object propertyValue);

	/**
	 * @param hql
	 *            the HQL query
	 * @return the HQL query result as <code>List</code>
	 */
	List<E> findByHQL(String hql);

	/**
	 * @param hql
	 *            the HQL query to be executed
	 * @param args
	 *            the parameters of the query
	 * @return the HQL query result as <code>List</code>
	 */
	List<E> findByHQL(String hql, Object[] args);

	/**
	 * Get the count of all the record in a table.
	 *
	 * @return
	 */
	long getCount();
}
